JavaScript'ning Obyektga Yo'naltirilgan Dasturlash evolyutsiyasini o'rganing. Prototip vorisligi, konstruktor andozalari, zamonaviy ES6 sinflari va kompozitsiya bo'yicha to'liq qo'llanma.
JavaScript Vorisligini O'zlashtirish: Sinf Andozalarini Chuqur O'rganish
Obyektga Yo'naltirilgan Dasturlash (OYD) zamonaviy dasturiy ta'minotni ishlab chiqishni shakllantirgan paradigmalar. Asosida, OYD bizga real dunyo obyektlarini modellashtirish, ma'lumotlarni (xususiyatlarni) va xatti-harakatlarni (metodlarni) birgalikda jamlash imkonini beradi. OYD ichidagi eng kuchli tushunchalardan biri bu vorislik — bir obyekt yoki sinf boshqasining xususiyatlari va metodlarini olish mexanizmi. JavaScript dunyosida vorislik o'ziga xos va qiziqarli tarixga ega bo'lib, u sof prototip modelidan bugungi kunda ko'rib turganimizdek, yanada tanish sinflarga asoslangan sintaksisga aylandi. Global dasturchilar auditoriyasi uchun bu andozalarni tushunish shunchaki akademik mashq emas; bu toza, qayta ishlatiladigan va kengaytiriladigan kod yozish uchun amaliy zaruratdir.
Ushbu keng qamrovli qo'llanma sizni JavaScript vorisligi landshafti bo'ylab sayohatga olib chiqadi. Biz fundamental prototip zanjiridan boshlaymiz, yillar davomida hukmronlik qilgan klassik andozalarni o'rganamiz, zamonaviy ES6 `class` sintaksisini tushuntiramiz va nihoyat, kompozitsiya kabi kuchli alternativalarni ko'rib chiqamiz. Siz asoslarni o'rganishga harakat qilayotgan yangi dasturchi bo'lasizmi yoki o'z tushunchangizni mustahkamlashni istagan tajribali mutaxassis bo'lasizmi, ushbu maqola sizga kerak bo'lgan aniqlik va chuqurlikni taqdim etadi.
Asos: JavaScript'ning Prototip Tabiatini Tushunish
Sinflar yoki vorislik andozalari haqida gapirishdan oldin, biz JavaScript'da bularning barchasini quvvatlaydigan fundamental mexanizmni tushunishimiz kerak: prototip vorisligi. Java yoki C++ kabi tillardan farqli o'laroq, JavaScript'da an'anaviy ma'noda sinflar mavjud emas. Buning o'rniga, obyektlar to'g'ridan-to'g'ri boshqa obyektlardan meros oladi. Har bir JavaScript obyekti `[[Prototype]]` sifatida ifodalanadigan shaxsiy xususiyatga ega bo'lib, u boshqa obyektga havola hisoblanadi. O'sha boshqa obyekt uning prototipi deb ataladi.
Prototip nima?
Siz obyektning xususiyatiga kirishga harakat qilganingizda, JavaScript dvigateli avval xususiyat obyektning o'zida mavjudligini tekshiradi. Agar mavjud bo'lmasa, u obyektning prototipiga qaraydi. Agar u yerda ham topilmasa, u prototipning prototipiga qaraydi va hokazo. Ushbu bog'langan prototiplar ketma-ketligi prototiplar zanjiri deb nomlanadi. Zanjir `null` bo'lgan prototipga yetganda tugaydi.
Keling, oddiy misolni ko'rib chiqaylik:
// Keling, andoza obyektini yaratamiz
const animal = {
breathes: true,
speak() {
console.log("This animal makes a sound.");
}
};
// 'animal'dan meros oluvchi yangi obyekt yaratamiz
const dog = Object.create(animal);
dog.name = "Buddy";
console.log(dog.name); // Natija: Buddy ('dog' obyektining o'zida topildi)
console.log(dog.breathes); // Natija: true ('dog'da emas, uning prototipi 'animal'da topildi)
dog.speak(); // Natija: This animal makes a sound. ('animal'da topildi)
console.log(Object.getPrototypeOf(dog) === animal); // Natija: true
Bu misolda, `dog` obyekti `animal` obyektidan meros oladi. Biz `dog.breathes` ni chaqirganimizda, JavaScript uni `dog`da topmaydi, shuning uchun `[[Prototype]]` havolasi orqali `animal`ga o'tadi va uni o'sha yerdan topadi. Bu prototip vorisligining eng sof shaklidir.
Prototip Zanjiri Amalda
Prototip zanjirini xususiyatlarni qidirish ierarxiyasi sifatida tasavvur qiling:
- Obyekt darajasi: `dog` obyekti `name` xususiyatiga ega.
- Prototip 1-daraja: `animal` (`dog`ning prototipi) `breathes` va `speak` xususiyatlariga ega.
- Prototip 2-daraja: `Object.prototype` (`animal`ning prototipi, chunki u literal sifatida yaratilgan) `toString()` va `hasOwnProperty()` kabi metodlarga ega.
- Zanjirning oxiri: `Object.prototype`ning prototipi `null`ga teng.
Bu zanjir JavaScript'dagi barcha vorislik andozalarining asosidir. Hatto biz ko'rib chiqadigan zamonaviy `class` sintaksisi ham aynan shu tizim ustiga qurilgan sintaktik qulaylikdir.
ES6'dan Oldingi JavaScript'dagi Klassik Vorislik Andozalari
ES6 (ECMAScript 2015) da `class` kalit so'zi kiritilishidan oldin, dasturchilar boshqa tillarda mavjud bo'lgan klassik vorislikni taqlid qilish uchun bir nechta andozalarni ishlab chiqdilar. Ushbu andozalarni tushunish eski kod bazalari bilan ishlash va ES6 sinflari nimalarni soddalashtirganini qadrlash uchun juda muhimdir.
1-andoza: Konstruktor Funksiyalari
Bu obyektlar uchun "andoza" yaratishning eng keng tarqalgan usuli edi. Konstruktor funksiyasi oddiy funksiyadir, lekin u `new` kalit so'zi bilan chaqiriladi.
Funksiya `new` bilan chaqirilganda, to'rtta narsa sodir bo'ladi:
- Yangi bo'sh obyekt yaratiladi va funksiyaning `prototype` xususiyatiga bog'lanadi.
- Funksiya ichidagi `this` kalit so'zi ushbu yangi obyektga bog'lanadi.
- Funksiya kodi bajariladi.
- Agar funksiya aniq bir obyektni qaytarmasa, 1-qadamda yaratilgan yangi obyekt qaytariladi.
function Vehicle(make, model) {
// Instansiya xususiyatlari - har bir obyekt uchun noyob
this.make = make;
this.model = model;
}
// Umumiy metodlar - xotirani tejash uchun prototipda mavjud
Vehicle.prototype.getDetails = function() {
return `${this.make} ${this.model}`;
};
const car1 = new Vehicle("Toyota", "Camry");
const car2 = new Vehicle("Honda", "Civic");
console.log(car1.getDetails()); // Natija: Toyota Camry
console.log(car2.getDetails()); // Natija: Honda Civic
// Ikkala instansiya ham bir xil getDetails funksiyasidan foydalanadi
console.log(car1.getDetails === car2.getDetails); // Natija: true
Ushbu andoza shablondan obyektlar yaratish uchun yaxshi ishlaydi, lekin o'z-o'zidan vorislikni ta'minlamaydi. Bunga erishish uchun dasturchilar uni boshqa usullar bilan birlashtirganlar.
2-andoza: Kombinatsiyalangan Vorislik (Klassik Andaza)
Bu yillar davomida eng ko'p qo'llaniladigan andoza edi. U ikkita texnikani birlashtiradi:
- Konstruktorni o'zlashtirish: Ota-ona konstruktorini bola kontekstida bajarish uchun `.call()` yoki `.apply()` dan foydalanish. Bu barcha instansiya xususiyatlarini meros qilib oladi.
- Prototip zanjirini qurish: Bolaning prototipini ota-onaning instansiyasiga o'rnatish. Bu barcha umumiy metodlarni meros qilib oladi.
Keling, `Vehicle`dan meros oladigan `Car` yaratamiz.
// Ota-ona Konstruktori
function Vehicle(make, model) {
this.make = make;
this.model = model;
}
Vehicle.prototype.getDetails = function() {
return `${this.make} ${this.model}`;
};
// Bola Konstruktori
function Car(make, model, numDoors) {
// 1. Konstruktorni o'zlashtirish: Instansiya xususiyatlarini meros olish
Vehicle.call(this, make, model);
this.numDoors = numDoors;
}
// 2. Prototip zanjirini qurish: Umumiy metodlarni meros olish
Car.prototype = Object.create(Vehicle.prototype);
// 3. Konstruktor xususiyatini to'g'rilash
Car.prototype.constructor = Car;
// Car uchun maxsus metod qo'shish
Car.prototype.honk = function() {
console.log("Beep beep!");
};
const myCar = new Car("Ford", "Focus", 4);
console.log(myCar.getDetails()); // Natija: Ford Focus (Vehicle.prototype'dan meros olingan)
console.log(myCar.numDoors); // Natija: 4
myCar.honk(); // Natija: Beep beep!
console.log(myCar instanceof Car); // Natija: true
console.log(myCar instanceof Vehicle); // Natija: true
Afzalliklari: Bu andoza mustahkam. U instansiya xususiyatlarini umumiy metodlardan to'g'ri ajratadi va `instanceof` tekshiruvlari uchun prototip zanjirini saqlaydi.
Kamchiliklari: U biroz ko'p so'zli va prototip hamda konstruktor xususiyatini qo'lda sozlashni talab qiladi. "Kombinatsiyalangan Vorislik" nomi ba'zan `Car.prototype = new Vehicle()` ishlatiladigan biroz kamroq optimal versiyaga ishora qiladi, bu esa `Vehicle` konstruktorini keraksiz ravishda ikki marta chaqiradi. Yuqorida ko'rsatilgan `Object.create()` usuli optimallashtirilgan yondashuv bo'lib, ko'pincha Parazit Kombinatsiyalangan Vorislik deb ataladi.
Zamonaviy Davr: ES6 Sinf Vorisligi
ECMAScript 2015 (ES6) obyektlar yaratish va vorislikni boshqarish uchun yangi sintaksisni taqdim etdi. `class` va `extends` kalit so'zlari boshqa OYD tillaridan kelgan dasturchilar uchun ancha toza va tanish sintaksisni ta'minlaydi. Biroq, shuni yodda tutish kerakki, bu JavaScript'ning mavjud prototip vorisligi ustidagi sintaktik shakardir. U yangi obyekt modelini joriy etmaydi.
`class` va `extends` Kalit So'zlari
Keling, `Vehicle` va `Car` misollarimizni ES6 sinflari yordamida qayta yozamiz. Natija ancha toza.
// Ota-ona Sinfi
class Vehicle {
constructor(make, model) {
this.make = make;
this.model = model;
}
getDetails() {
return `${this.make} ${this.model}`;
}
}
// Bola Sinfi
class Car extends Vehicle {
constructor(make, model, numDoors) {
// Ota-ona konstruktorini super() bilan chaqirish
super(make, model);
this.numDoors = numDoors;
}
honk() {
console.log("Beep beep!");
}
}
const myCar = new Car("Tesla", "Model 3", 4);
console.log(myCar.getDetails()); // Natija: Tesla Model 3
myCar.honk(); // Natija: Beep beep!
console.log(myCar instanceof Car); // Natija: true
console.log(myCar instanceof Vehicle); // Natija: true
`super()` Metodi
`super` kalit so'zi muhim qo'shimchadir. Uni ikki xil usulda ishlatish mumkin:
- Funksiya sifatida `super()`: Bola sinfining konstruktori ichida chaqirilganda, u ota-ona sinfining konstruktorini chaqiradi. Bola sinf konstruktorida `this` kalit so'zini ishlatishdan oldin `super()` ni chaqirishingiz shart. Buning sababi, `this` kontekstini yaratish va initsializatsiya qilish uchun ota-ona konstruktori mas'uldir.
- Obyekt sifatida `super.methodName()`: Uni ota-ona sinfidagi metodlarni chaqirish uchun ishlatish mumkin. Bu xatti-harakatni to'liq qayta yozish o'rniga uni kengaytirish uchun foydalidir.
class Employee {
constructor(name) {
this.name = name;
}
getGreeting() {
return `Salom, mening ismim ${this.name}.`;
}
}
class Manager extends Employee {
constructor(name, department) {
super(name); // Ota-ona konstruktorini chaqirish
this.department = department;
}
getGreeting() {
// Ota-ona metodini chaqirish va uni kengaytirish
const baseGreeting = super.getGreeting();
return `${baseGreeting} Men ${this.department} bo'limini boshqaraman.`;
}
}
const manager = new Manager("Jane Doe", "Technology");
console.log(manager.getGreeting());
// Natija: Salom, mening ismim Jane Doe. Men Technology bo'limini boshqaraman.
Parda Orqasida: Sinflar "Maxsus Funksiyalar"dir
Agar sinfning `typeof`ini tekshirsangiz, uning funksiya ekanligini ko'rasiz.
class MyClass {}
console.log(typeof MyClass); // Natija: "function"
`class` sintaksisi biz uchun avval qo'lda qilishimiz kerak bo'lgan bir nechta narsalarni avtomatik ravishda bajaradi:
- Sinf tanasi qat'iy rejimda (strict mode) bajariladi.
- Sinf metodlari sanab bo'lmaydigan (non-enumerable) hisoblanadi.
- Sinflarni `new` bilan chaqirish shart; ularni oddiy funksiya sifatida chaqirish xatolikka olib keladi.
- `extends` kalit so'zi prototip zanjirini sozlashni (`Object.create()`) bajaradi va `super`dan foydalanish imkonini beradi.
Bu sintaktik shakar kodni ancha o'qiladigan va xatolardan xoli qiladi, prototip manipulyatsiyasining ortiqcha qismlarini yashiradi.
Statik Metodlar va Xususiyatlar
Sinflar `static` a'zolarni aniqlash uchun ham toza usulni taqdim etadi. Bular sinfning biron bir instansiyasiga emas, balki sinfning o'ziga tegishli bo'lgan metodlar va xususiyatlardir. Ular yordamchi funksiyalarni yaratish yoki sinfga oid konstantalarni saqlash uchun foydalidir.
class TemperatureConverter {
// Statik xususiyat
static ABSOLUTE_ZERO_CELSIUS = -273.15;
// Statik metod
static celsiusToFahrenheit(celsius) {
return (celsius * 9/5) + 32;
}
static fahrenheitToCelsius(fahrenheit) {
return (fahrenheit - 32) * 5/9;
}
}
// Siz statik a'zolarni to'g'ridan-to'g'ri sinfda chaqirasiz
console.log(`Suvning qaynash nuqtasi ${TemperatureConverter.celsiusToFahrenheit(100)}°F.`);
// Natija: Suvning qaynash nuqtasi 212°F.
const converterInstance = new TemperatureConverter();
// converterInstance.celsiusToFahrenheit(100); // Bu TypeError xatosini beradi
Klassik Vorislikdan Tashqari: Kompozitsiya va Miksinlar
Sinflarga asoslangan vorislik kuchli bo'lsa-da, u har doim ham eng yaxshi yechim emas. Vorislikka haddan tashqari tayanish o'zgartirish qiyin bo'lgan chuqur, qattiq ierarxiyalarga olib kelishi mumkin. Bu ko'pincha "gorilla/banan muammosi" deb ataladi: siz banan xohlagan edingiz, lekin siz bananni ushlab turgan gorilla va u bilan butun o'rmonni oldingiz. Zamonaviy JavaScript'dagi ikkita kuchli alternativa bu kompozitsiya va miksinlardir.
Vorislikdan Ustun Kompozitsiya: "Has-A" Munosabati
"Vorislikdan ustun kompozitsiya" tamoyili shuni ko'rsatadiki, obyektlarni katta, monolit asosiy sinfdan meros olish o'rniga, kichikroq, mustaqil qismlardan tashkil topgan holda yaratish afzalroqdir. Vorislik "is-a" (bir turi) munosabatini aniqlaydi (`Car` bir turi `Vehicle`). Kompozitsiya esa "has-a" (...ga ega) munosabatini aniqlaydi (`Car` bir `Engine`ga ega).
Keling, har xil turdagi robotlarni modellashtiraylik. Chuqur vorislik zanjiri shunday ko'rinishi mumkin: `Robot -> FlyingRobot -> RobotWithLasers`.
Bu mo'rt bo'lib qoladi. Agar siz lazerli yuradigan robotni xohlasangiz-chi? Yoki lazersiz uchadigan robotni? Kompozitsion yondashuv ancha moslashuvchan.
// Imkoniyatlarni funksiyalar (fabrikalar) sifatida aniqlash
const canFly = (state) => ({
fly: () => console.log(`${state.name} uchmoqda!`)
});
const canShootLasers = (state) => ({
shoot: () => console.log(`${state.name} lazer otmoqda!`)
});
const canWalk = (state) => ({
walk: () => console.log(`${state.name} yurmoqda.`)
});
// Robotni imkoniyatlarni birlashtirib yaratish
const createFlyingLaserRobot = (name) => {
let state = { name };
return Object.assign(
{},
state,
canFly(state),
canShootLasers(state)
);
};
const createWalkingRobot = (name) => {
let state = { name };
return Object.assign(
{},
state,
canWalk(state)
);
}
const robot1 = createFlyingLaserRobot("T-8000");
robot1.fly(); // Natija: T-8000 uchmoqda!
robot1.shoot(); // Natija: T-8000 lazer otmoqda!
const robot2 = createWalkingRobot("C-3PO");
robot2.walk(); // Natija: C-3PO yurmoqda.
Ushbu andoza ajoyib darajada moslashuvchan. Siz qattiq sinf ierarxiyasi bilan cheklanmasdan xatti-harakatlarni kerak bo'lganda aralashtirib, moslashtirishingiz mumkin.
Miksinlar: Funksionallikni Kengaytirish
Miksin - bu boshqa sinflar o'sha sinflarning ota-onasi bo'lmasdan turib ishlatishi mumkin bo'lgan metodlarni taqdim etuvchi obyekt yoki funksiya. Bu funksionallikni "aralashtirish" usulidir. Bu hatto ES6 sinflari bilan ham ishlatilishi mumkin bo'lgan kompozitsiya shaklidir.
Keling, har qanday sinfga qo'llanilishi mumkin bo'lgan `withLogging` miksinini yarataylik.
// Miksin
const withLogging = {
log(message) {
console.log(`[LOG] ${new Date().toISOString()}: ${message}`)
},
logError(message) {
console.error(`[ERROR] ${new Date().toISOString()}: ${message}`)
}
};
class DatabaseService {
constructor(connectionString) {
this.connectionString = connectionString;
}
connect() {
this.log(`Connecting to ${this.connectionString}...`);
// ... ulanish mantig'i
this.log("Connection successful.");
}
}
// Object.assign yordamida funksionallikni sinf prototipiga aralashtirish
Object.assign(DatabaseService.prototype, withLogging);
const db = new DatabaseService("mongodb://localhost/mydb");
db.connect();
// [LOG] 2023-10-27T10:00:00.000Z: Connecting to mongodb://localhost/mydb...
// [LOG] 2023-10-27T10:00:00.000Z: Connection successful.
db.logError("Failed to fetch user data.");
// [ERROR] 2023-10-27T10:00:00.000Z: Failed to fetch user data.
Ushbu yondashuv sizga umumiy funksionallikni, masalan, loglash, serializatsiya yoki hodisalarni qayta ishlashni, bir-biriga bog'liq bo'lmagan sinflar bo'ylab ularni vorislik munosabatiga majburlamasdan bo'lishish imkonini beradi.
To'g'ri Andozani Tanlash: Amaliy Qo'llanma
Shuncha ko'p variantlar mavjud bo'lsa, qaysi andozani ishlatishni qanday hal qilasiz? Global ishlab chiqish jamoalari uchun oddiy qo'llanma:
-
Aniq "is-a" munosabatlari uchun ES6 sinflaridan (`extends`) foydalaning.
Sizda aniq, ierarxik taksonomiya mavjud bo'lganda, `class` vorisligi eng o'qiladigan va an'anaviy yondashuvdir. `Manager` bu `Employee`. `SavingsAccount` bu `BankAccount`. Ushbu andoza yaxshi tushunilgan va eng zamonaviy JavaScript sintaksisidan foydalanadi.
-
Ko'p imkoniyatlarga ega murakkab obyektlar uchun Kompozitsiyani afzal ko'ring.
Obyekt bir nechta, mustaqil va almashtiriladigan xatti-harakatlarga ega bo'lishi kerak bo'lganda, kompozitsiya ustunroqdir. Bu chuqur ichma-ichlikni oldini oladi va yanada moslashuvchan, bog'liqligi kam kod yaratadi. Sudraladigan, o'lchami o'zgartiriladigan va yig'iladigan kabi xususiyatlarga muhtoj bo'lgan foydalanuvchi interfeysi komponentini yaratish haqida o'ylang. Bular chuqur vorislik zanjiridan ko'ra, kompozitsiyalangan xatti-harakatlar sifatida yaxshiroqdir.
-
Umumiy yordamchi dasturlar to'plamini bo'lishish uchun Miksinlardan foydalaning.
Sizda ko'p turli xil obyektlarga (loglash, nosozliklarni tuzatish yoki ma'lumotlarni serializatsiya qilish kabi) tegishli bo'lgan funksionallik - o'zaro kesishuvchi masalalar mavjud bo'lganda, miksinlar bu xatti-harakatni asosiy vorislik daraxtini chalkashtirmasdan qo'shishning ajoyib usulidir.
-
Prototip Vorisligini o'z poydevoringiz sifatida tushuning.
Qaysi yuqori darajadagi andozadan foydalanishingizdan qat'i nazar, JavaScript'da hamma narsa prototip zanjiriga borib taqalishini unutmang. Ushbu poydevorni tushunish sizga murakkab muammolarni bartaraf etish va tilning obyekt modelini chinakamiga o'zlashtirish imkonini beradi.
Xulosa: JavaScript OYD'ning Rivojlanayotgan Manzarasi
JavaScript'ning Obyektga Yo'naltirilgan Dasturlashga yondashuvi uning til sifatida rivojlanishining bevosita aksidir. U oddiy, kuchli va ba'zan noto'g'ri tushunilgan prototip tizimidan boshlandi. Vaqt o'tishi bilan, dasturchilar klassik vorislikni taqlid qilish uchun ushbu tizim ustiga andozalar qurdilar. Bugungi kunda, ES6 sinflari bilan, biz OYDni o'zining prototip ildizlariga sodiq qolgan holda yanada qulayroq qiladigan toza, zamonaviy sintaksisga egamiz.
Dunyo bo'ylab zamonaviy dasturiy ta'minotni ishlab chiqish yanada moslashuvchan va modulli arxitekturalarga o'tayotganligi sababli, kompozitsiya va miksinlar kabi andozalar mashhurlikka erishdi. Ular ba'zan chuqur vorislik ierarxiyalari bilan birga keladigan qattiqlikka kuchli alternativa taklif qiladi. Malakali JavaScript dasturchisi faqat bitta andozani tanlamaydi; u butun asboblar qutisini tushunadi. Ular aniq sinf ierarxiyasi qachon to'g'ri tanlov ekanligini, obyektlarni kichikroq qismlardan qachon tuzish kerakligini va asosdagi prototip zanjiri bularning barchasini qanday amalga oshirishini biladilar. Ushbu andozalarni o'zlashtirib, siz keyingi loyihangiz qanday qiyinchiliklarni keltirishidan qat'i nazar, yanada mustahkam, qo'llab-quvvatlanadigan va nafis kod yozishingiz mumkin.